import React, { useEffect, useState, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { NavBar, Toast } from "antd-mobile";
import { List, AutoSizer } from "react-virtualized"; //导入list组件
import axios from "axios";
import "./index.css";

//格式化城市字母索引
function formatCityIndex(letter) {
  switch (letter) {
    case "#":
      return "当前定位";
    case "hot":
      return "热门城市";
    default:
      return letter.toUpperCase();
  }
}

export default function CityList() {
  const [state, setState] = useState({
    cityList: {},
    cityIndex: [],
    activeIndex: 0,
  });
  const navigate = useNavigate();
  const cityListComponent = useRef(null);
  useEffect(() => {
    getCityList();
  }, []);

  //有房源的城市
  const HOUSE_CITY = ["北京", "上海", "广州", "深圳"];

  //切换城市
  function changeCity({ label, value }) {
    if (HOUSE_CITY.includes(label)) {
      //有房源信息
      //将城市信息保存在本地
      localStorage.setItem("hkzf_city", JSON.stringify({ label, value }));
      //返回到上一页
      navigate(-1);
    } else {
      //无房源信息
      Toast.info("该城市暂无房源信息", 1, null, false);
    }
  }

  //渲染城市列表每一行数据
  function rowRenderer({
    key, //唯一标识
    index, // 索引号
    isScrolling, // 当前项是否正在滚动中
    isVisible, // 当前项在list列表中是可见的
    style, // 注意:重点数据,每一项都要添加此样式  作用:指定每一行的位置
  }) {
    //获取每一行字母索引
    const { cityIndex, cityList } = state;
    const letter = cityIndex[index];
    //获取指定字母下的城市数据
    // cityList[letter]

    // measureAllRows()提前计算list中每一行的高度,实现scrollToRow的精确跳转
    // 注意:要保证list组件中已经有数据了,数据为空就会报错  保证该方法在获取数据之后调用 async await
    cityListComponent.current.measureAllRows();

    return (
      <div key={key} style={style} className="city">
        <div className="title">{formatCityIndex(letter)}</div>
        {cityList[letter].map((item) => (
          <div
            className="name"
            key={item.value}
            onClick={() => {
              changeCity(item);
            }}
          >
            {item.label}
          </div>
        ))}
      </div>
    );
  }

  //城市数据格式化
  //原始数据:{label: '北京', value: 'AREA|88cff55c-aaa4-e2e0', pinyin: 'beijing', short: 'bj'}
  // 城市列表数据格式:{a:[{},{}],b:[{},{}]}
  // 索引数据格式:['a','b']
  async function formatCityData(list) {
    const cityList = {};
    // - 遍历  list数组
    list.forEach((item) => {
      // - 获取到每一个城市的首字母
      const first = item.short.substr(0, 1);
      // - 判断我们定义的数组中是否有这个分类，如果有，那么直接push数据进来，如果没有，添加这个分类
      if (cityList[first]) {
        // 如果有，那么直接push数据进来
        cityList[first].push(item);
      } else {
        // 如果没有，添加这个分类
        cityList[first] = [item];
      }
    });
    //获取索引数据
    const cityIndex = Object.keys(cityList).sort();
    const hotCityList = await getHotCity();
    //热门城市数据，添加到`cityList` 列表数据中
    cityList["hot"] = hotCityList;
    //将索引数据添加到 `cityIndex` 索引数据中
    cityIndex.unshift("hot");
    const curCity = await getCurrentCity();
    //当前城市数据，添加到`cityList` 列表数据中
    cityList["#"] = [curCity];
    // 将索引数据添加到 `cityIndex` 索引数据中
    cityIndex.unshift("#");

    return {
      cityList,
      cityIndex,
    };
  }

  //获取城市列表数据
  async function getCityList() {
    const res = await axios.get("http://localhost:8080/area/city?level=1");
    const { cityList, cityIndex } = await formatCityData(res.data.body);

    setState((preState) => {
      return {
        ...preState,
        cityList,
        cityIndex,
      };
    });
  }

  //获取热门城市数据
  async function getHotCity() {
    const res = await axios.get("http://localhost:8080/area/hot");
    return res.data.body;
  }

  //获取当前城市+城市数据
  async function getCurrentCity() {
    // 获取本地存储中是否有
    let localCity = JSON.parse(localStorage.getItem("localCity"));
    if (!localCity) {
      // 如果没有，就需要获取当前定位城市
      // 利用 promis 来解决异步数据的返回
      return new Promise((resolve, reject) => {
        try {
          // 获取当前城市信息
          var myCity = new window.BMapGL.LocalCity();
          myCity.get(async (res) => {
            // 当获取到对应的城市信息了后，我们需要请求我们自己的服务器
            const { data: infoRes } = await axios.get(
              "http://localhost:8080/area/info",
              {
                params: {
                  name: res.name,
                },
              }
            );
            if (infoRes.status !== 200) {
              console.error(infoRes.description);
              return;
            }
            console.log(infoRes);

            // res.data.body
            // 保存在本地存储中
            localStorage.setItem("localCity", JSON.stringify(infoRes.body));
            // 返回城市的数据
            resolve(infoRes.body);
          });
        } catch (error) {
          // 进入到catch代码块 说明调用失败了
          reject(error);
        }
      });
    }
    // 如果有，我们直接返回城市信息就好,返回一个成功的promis对象即可
    return Promise.resolve(localCity);
  }

  //索引AB的高度
  const TITLE_HEIGHT = 36;
  //城市名称的高度
  const NAME_HEIGHT = 50;

  //动态计算每一行的高度
  function getRowHeight({ index }) {
    const { cityIndex, cityList } = state;
    return TITLE_HEIGHT + NAME_HEIGHT * cityList[cityIndex[index]].length;
  }

  //渲染索引列表
  function renderCityIndex() {
    return state.cityIndex.map((item, index) => {
      return (
        <li
          className="city-index-item"
          key={item}
          onClick={() => {
            //调用List组件实例中的scrollToRow方法,滚动列表  跳转的必须是页面加载过的  解决方法:提前计算所有行高度
            cityListComponent.current.scrollToRow(index);
          }}
        >
          {/*判断一下，如果高亮状态的索引等于当前索引，那么就设置高亮样式*/}
          <span className={state.activeIndex === index ? "index-active" : ""}>
            {item === "hot" ? "热" : item.toUpperCase()}
          </span>
        </li>
      );
    });
  }

  //用于获取list组件中渲染行的信息
  function onRowsRendered({ startIndex }) {
    if (state.activeIndex !== startIndex) {
      setState((preState) => {
        return {
          ...preState,
          activeIndex: startIndex,
        };
      });
    }
  }

  return (
    <div className="citylist">
      <NavBar
        className="navbar"
        // 模式 默认值是 dark
        mode="light"
        // 左侧小图片
        icon={<i className="iconfont icon-back" />}
        // 左侧按钮的点击事件
        onLeftClick={() => navigate(-1)}
      >
        城市选择
      </NavBar>
      <AutoSizer>
        {({ width, height }) => (
          <List
            ref={cityListComponent}
            scrollToAlignment="start" //滚动到改行的起始位置
            width={width}
            height={height}
            rowCount={state.cityIndex.length}
            rowHeight={getRowHeight}
            rowRenderer={rowRenderer}
            onRowsRendered={onRowsRendered}
          />
        )}
      </AutoSizer>

      {/* 右侧索引列表 */}
      <ul className="city-index">{renderCityIndex()}</ul>
    </div>
  );
}
